#include "bsp_tm1650.h"
#include "bsp_iic.h"
/*
注意：通讯协议只是和IIC类似，但不是标准IIC
*/

//不带小数点
 uint8_t NUM_TAB[18] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7C,0x39,0x5E,0x79,0x71,0x70,0x00}; //0x79(E)  0x70(r)  
                     // 0    1    2    3    4    5    6    7    8    9			A    b   C    d     E    F   r   无显示
//带小数点				 
uint8_t NUM_DP_TAB[11] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0x80}; //0~9显示代码,最后一位全关，只留下小数点
												// 0    1    2    3    4    5    6    7    8    9


static void TM1650_Set(uint8_t add,uint8_t dat); //数码管显示
I2C *TM1650_I2C;
/****************************
数码管接口初始化，其中时钟的点使用PWM控制，方便控制周期闪烁
****************************/
void TM1650_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
	RCC_APB2PeriphClockCmd(POINT_LED_RCC | RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); 

	GPIO_InitStructure.GPIO_Pin = POINT_LED_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init( POINT_LED_PORT, &GPIO_InitStructure );
	
	TIM_TimeBaseStructure.TIM_Prescaler = TIMER1_PRESCALER;   
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = TIMER1_PERIOD;   
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OCInitStructure.TIM_Pulse = TIMER1_PULSE;
	
	TIM_OC3Init(TIM1, &TIM_OCInitStructure);  
	TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);  
 
	TIM_Cmd(TIM1, ENABLE);  //使能TIM3
	// TIM1 Main Output Enable 
  TIM_CtrlPWMOutputs(TIM1, ENABLE);
	
	
	// 通讯接口初始化
  RCC_APB2PeriphClockCmd(TM1650_RCC, ENABLE);	    
	GPIO_InitStructure.GPIO_Pin = TM1650_SDA_PIN | TM1650_CLK_PIN;              
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;           
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(TM1650_PORT, &GPIO_InitStructure); 	
//	I2C_GPIO_Config();
//	TM1650_I2C = I2C_1;
	POINT_LED_OFF;
	
	//设定亮度，开显示八段显示方式，后一个字节中高位用于亮度，低位用于七段或八段显示方式和开关显
  //如：0x71为七级亮度，八段显示方式，开显示；0x79为为七级亮度，七段显示方式，开显示 
	TM1650_Set(TM1650_CMD,TM1650_BL*16+0x01);
	

	tm1650.hh = 0;
	tm1650.pointStat = OFF;
	tm1650.mm = 0;
	TM1650_UpdataNum(0);
}

// 约390ns
static void TM1650_Delay(void){
	uint8_t i=0;
}


static void TM1650_Start(void){//开始信号
		TM1650_CLK = 1;
		TM1650_SDA = 1;
		TM1650_Delay();
		TM1650_SDA = 0;
		TM1650_Delay();
		TM1650_CLK = 0;
		TM1650_Delay();
}

static void TM1650_Ask(void){ //ACK信号
		uint8_t timeout = 1;
		TM1650_CLK = 1;
		TM1650_Delay();
		TM1650_CLK = 0;
		while((TM1650_SDA)&&(timeout<=100)){
				timeout++;
		}
		TM1650_Delay();
		TM1650_CLK = 0;
}

static void TM1650_Stop(void){ //停止信号
		TM1650_CLK = 1;
		TM1650_Delay();
		TM1650_SDA = 0;
		TM1650_Delay();
		TM1650_SDA = 1;
}

static void TM1650_WriteByte(uint8_t oneByte){//写一个字节高位在前，低位在后
		int8_t i;
		for(i=7;i>=0;i--){
				TM1650_SDA = (oneByte>>i)&0x01;
				TM1650_CLK = 0;
				TM1650_Delay();
				TM1650_CLK = 1;
				TM1650_Delay();
				TM1650_CLK = 0;
				TM1650_Delay();
		}
}



/*写数据*/
static void TM1650_Set(uint8_t add,uint8_t dat){ //数码管显示
		//写显存必须从高地址开始写
		TM1650_Start();
		TM1650_WriteByte(add); //第一个显存地址
		TM1650_Ask();
		TM1650_WriteByte(dat);
		TM1650_Ask();
		TM1650_Stop();
}


/******************************
	更新小数点的显示状态
******************************/
void TM1650_POINT_Updata(LED_STAT stat)
{
	static LED_STAT statLast = IDEL;
	if(stat!=statLast || stat==TOGGLE){  // 状态切换和呼吸灯需要周期执行
		switch(stat){
			case OFF:			POINT_LED_OFF;		break;
			case ON:			POINT_LED_ON;			break;
			case TOGGLE:	POINT_LED_TOGGLE;	break;
			default:break;
		}
	}
	statLast = stat;
}


/******************************
	刷新数码管显示参数，供应用层调用
hh：小时
point：中间的点显示状态
mm：分钟
******************************/
void TM1650_SetTime(uint8_t hh,LED_STAT pointStat,uint8_t mm)
{
	tm1650.hh = hh;
	tm1650.pointStat = pointStat;
	tm1650.mm = mm;
}

/******************************
	刷新数码管时间显示，放在循环中周期调用
hh：小时
point：中间的点显示状态
mm：分钟
******************************/
void TM1650_UpdataTime(uint8_t hh,LED_STAT pointStat,uint8_t mm)
{
	static uint8_t hhLast=0xff,mmLast=0xff;
	static LED_STAT pointStatLast = IDEL;
	if(hh!=hhLast || mm!=mmLast || pointStatLast!=pointStat)
	{
		TM1650_Set(TM1650_NUM1, NUM_TAB[hh/10]);
		TM1650_Set(TM1650_NUM2, NUM_TAB[hh%10]);
		TM1650_POINT_Updata(pointStat);
		TM1650_Set(TM1650_NUM3, NUM_TAB[mm/10]);
		TM1650_Set(TM1650_NUM4, NUM_TAB[mm%10]);
	}
	hhLast = hh;
	mmLast = mm;
	pointStatLast = pointStat;
}

// 显示数字0~9999,前面的0不显示
void TM1650_UpdataNum(uint16_t num)
{
static uint16_t numLast=10000;
	uint8_t count = 4;
	TM1650_POINT_Updata(OFF);
	if(num!=numLast)
	{
		if(num/1000==0)									count = 3;
		if(num/100%10==0 && count==3)		count = 2;
		if(num/10%10==0 && count==2)				count = 1;
		
		switch(count)
		{
			case 4:{
					TM1650_Set(TM1650_NUM1, NUM_TAB[num/1000]);
					TM1650_Set(TM1650_NUM2, NUM_TAB[num/100%10]);
					TM1650_Set(TM1650_NUM3, NUM_TAB[num/10%10]);
				}break;
			case 3:{
					TM1650_Set(TM1650_NUM1, 0x00);
					TM1650_Set(TM1650_NUM2, NUM_TAB[num/100%10]);
					TM1650_Set(TM1650_NUM3, NUM_TAB[num/10%10]);
				}break;
			case 2:{
					TM1650_Set(TM1650_NUM1, 0x00);
					TM1650_Set(TM1650_NUM2, 0x00);
					TM1650_Set(TM1650_NUM3, NUM_TAB[num/10%10]);
				}break;
				case 1:{
					TM1650_Set(TM1650_NUM1, 0x00);
					TM1650_Set(TM1650_NUM2, 0x00);
					TM1650_Set(TM1650_NUM3, 0x00);
				}break;
		}
		
		TM1650_Set(TM1650_NUM4, NUM_TAB[num%10]);
	}
	numLast = num;
}

// 显示Err
void TM1650_UpdataErr(void)
{
		TM1650_Set(TM1650_NUM1, 0x00);
		TM1650_Set(TM1650_NUM2, 0x79);
		TM1650_Set(TM1650_NUM3, 0x70);
		TM1650_Set(TM1650_NUM4, 0x70);
}


void TM1650_Test(void)
{
	static uint16_t time=0;  // 数码管测试
	time++;
	if(time>9999)  time=0;
	TM1650_UpdataNum(time);
}